Skip to content

Conversation

@Akshay2191
Copy link
Contributor

Extends the ConfigApply capability to manage NGINX configurations that reference external resources hosted at remote URLs. The agent now handles downloading of these files into the NGINX configuration directory before applying the new configuration.

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have read the CONTRIBUTING document
  • I have run make install-tools and have attached any dependency changes to this pull request
  • If applicable, I have added tests that prove my fix is effective or that my feature works
  • If applicable, I have checked that any relevant tests pass after adding my changes
  • If applicable, I have updated any relevant documentation (README.md)
  • If applicable, I have tested my cross-platform changes on Ubuntu 22, Redhat 8, SUSE 15 and FreeBSD 13

@Akshay2191 Akshay2191 requested a review from a team as a code owner November 12, 2025 15:50
@github-actions github-actions bot added the chore Pull requests for routine tasks label Nov 12, 2025
@codecov
Copy link

codecov bot commented Nov 12, 2025

Codecov Report

❌ Patch coverage is 89.82301% with 23 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.38%. Comparing base (b1947ec) to head (4a2b917).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
internal/file/file_manager_service.go 87.73% 12 Missing and 8 partials ⚠️
internal/config/config.go 95.23% 1 Missing and 1 partial ⚠️
internal/file/file_service_operator.go 95.23% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1389      +/-   ##
==========================================
+ Coverage   86.31%   86.38%   +0.06%     
==========================================
  Files         102      102              
  Lines       12603    12798     +195     
==========================================
+ Hits        10878    11055     +177     
- Misses       1249     1260      +11     
- Partials      476      483       +7     
Files with missing lines Coverage Δ
internal/config/defaults.go 100.00% <ø> (ø)
internal/config/flags.go 100.00% <ø> (ø)
internal/config/types.go 87.65% <ø> (ø)
internal/model/config.go 90.47% <ø> (ø)
internal/file/file_service_operator.go 77.32% <95.23%> (+1.18%) ⬆️
internal/config/config.go 87.60% <95.23%> (+0.29%) ⬆️
internal/file/file_manager_service.go 78.77% <87.73%> (+3.38%) ⬆️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b1947ec...4a2b917. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@Akshay2191 Akshay2191 self-assigned this Nov 19, 2025
fs.Duration(
ClientFileDownloadTimeoutKey,
DefClientFileDownloadTimeout,
"Timeout value in seconds, to downloading file for config apply.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Timeout value in seconds, to downloading file for config apply.",
"Timeout value in seconds, for downloading a file during a config apply.",

fs.String(
ExternalDataSourceProxyUrlKey,
DefExternalDataSourceProxyUrl,
"Url to the proxy service to fetch the external file.",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Url to the proxy service to fetch the external file.",
"Url to the proxy service for fetching external files.",

})
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test for external Data source and add the external data source to TestResolveConfig() which checks all the values that can be set in the agent config

filesMutex sync.RWMutex
currentFilesOnDisk map[string]*mpi.File // key is file path
previousManifestFiles map[string]*model.ManifestFile
newExternalFileHeaders map[string]DownloadHeaders
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
newExternalFileHeaders map[string]DownloadHeaders
externalFileHeaders map[string]DownloadHeaders

fileDiff[fileName] = modifiedFile

continue
// if file currently exists and file hash is different, file has been updated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was the continue removed ?


continue
case model.Delete, model.Update:
case model.Delete, model.Update, model.ExternalFile:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the external files are the files still considered updated, added or deleted? Just wondering instead should it be a field added to the file rather than an action this might fix a few of the things the linter had an issue with which required the checking of Adding and updating in the switch statement

headers.ETag = resp.Header.Get("ETag")
headers.LastModified = resp.Header.Get("Last-Modified")
case http.StatusNotModified:
slog.InfoContext(ctx, "File content unchanged (304 Not Modified)", "file_name", fileName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
slog.InfoContext(ctx, "File content unchanged (304 Not Modified)", "file_name", fileName)
slog.DebugContext(ctx, "File content unchanged (304 Not Modified)", "file_name", fileName)

}
}

func isWildcardMatch(hostname, pattern string) bool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the naming of this be changed

return false
}

for _, pattern := range allowedDomains {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for _, pattern := range allowedDomains {
for _, domain := range allowedDomains {

"github.com/stretchr/testify/require"
)

type fakeFSO struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have a fake file operator in agent/internal/file/filefakes/fake_file_operator.go

fs.Duration(
ClientFileDownloadTimeoutKey,
DefClientFileDownloadTimeout,
"Timeout value in seconds, to downloading file for config apply.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"Timeout value in seconds, to downloading file for config apply.",
"Timeout value in seconds, to download a file during a config apply request.",


for _, domain := range domains {
if strings.ContainsAny(domain, "/\\ ") || domain == "" {
slog.Error("domain is not specified in allowed_domains")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need to log error here if you are returning the error anyways

}

for _, domain := range domains {
if strings.ContainsAny(domain, "/\\ ") || domain == "" {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way to validate if the string is a valid domain name or not? Maybe there is a regex we could use?

DefLibDir = "/var/lib/nginx-agent"

DefExternalDataSourceProxyUrl = ""
DefExternalDataSourceMaxBytes = 100 * 1024 * 1024
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add a comment to say what the default size is in MB

return fso.sendUpdateFileStream(ctx, fileToUpdate, fso.agentConfig.Client.Grpc.FileChunkSize)
}

func (fso *FileServiceOperator) RenameExternalFile(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of duplicating the RenameFile function can we update the RenameFile function to just rename the file and have the hash validation in a separate function like this:

func (fso *FileServiceOperator) RenameAndValidateFile(
  ctx context.Context, source, destination string,
) error {
  err := fso.RenameFile(ctx, source, destination)
  if err != nil {
    return err
  }

 return fso.validateFileHash(desination, hash)
}

executePerm = 0o111
)

type DownloadHeaders struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
type DownloadHeaders struct {
type DownloadHeader struct {

modifiedFile.Action = model.Update
fileDiff[fileName] = modifiedFile
}
if modifiedFile.File.GetExternalDataSource() != nil || currentFile.GetExternalDataSource() != nil {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move this if statement up to just after line 404? It will save you from doing unnecessary os.Stat

Comment on lines +822 to +824
func (fms *FileManagerService) handleExternalFileDownload(ctx context.Context, fileAction *model.FileCache,
tempFilePath string,
) error {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
func (fms *FileManagerService) handleExternalFileDownload(ctx context.Context, fileAction *model.FileCache,
tempFilePath string,
) error {
func (fms *FileManagerService) downloadExternalFile(ctx context.Context, fileAction *model.FileCache,
filePath string,
) error {

ctx,
content,
path,
"0600",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the file permissions should come from the file meta in the File proto message

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Pull requests for routine tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants